package com.sunrise.xdoc.utils;

import java.awt.Color;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.imageio.ImageIO;

public class ImageUtils {

	/***
	 * Zoom in or out the image until it fits size both height and width. Then
	 * cut 50% each side so image is centered
	 * 
	 * @param originalImage
	 *            image need to be implemented zoom option
	 * @param canVasWidth
	 *            width of widget
	 * @param canVasHeight
	 *            height of widget
	 * @return BufferedImage image after zooming
	 */
	public static BufferedImage zoomImage(BufferedImage originalImage, int canVasWidth, int canVasHeight) {
		BufferedImage zoomedImage = null;

		int imageWidth = originalImage.getWidth();
		int imageHeight = originalImage.getHeight();
		double ratio = 0.0;

		if (canVasWidth == canVasHeight) {
			if (imageWidth <= imageHeight) {
				ratio = (double) imageWidth / imageHeight;
				double newImageHeight = (double) canVasWidth / ratio;
				Image scaledWidthImage = originalImage.getScaledInstance(canVasWidth, (int) newImageHeight,
						Image.SCALE_AREA_AVERAGING);
				zoomedImage = new BufferedImage(canVasWidth, canVasHeight, originalImage.getType());
				zoomedImage.getGraphics().drawImage(scaledWidthImage, 0, -(int) (newImageHeight - canVasHeight) / 2,
						null);
			} else {
				ratio = (double) imageHeight / imageWidth;
				double newImageWidth = (double) canVasHeight / ratio;
				Image scaledHeightImage = originalImage.getScaledInstance((int) newImageWidth, canVasHeight,
						Image.SCALE_AREA_AVERAGING);
				zoomedImage = new BufferedImage(canVasWidth, canVasHeight, originalImage.getType());
				zoomedImage.getGraphics().drawImage(scaledHeightImage, -(int) (newImageWidth - canVasWidth) / 2, 0,
						null);
			}
		} else {
			ratio = (double) imageWidth / imageHeight;
			double newImageHeight = (double) canVasWidth / ratio;
			Image scaledWidthImage = null;

			if (newImageHeight > canVasHeight) {
				scaledWidthImage = originalImage.getScaledInstance(canVasWidth, (int) newImageHeight,
						Image.SCALE_AREA_AVERAGING);
				zoomedImage = new BufferedImage(canVasWidth, canVasHeight, originalImage.getType());
				zoomedImage.getGraphics().drawImage(scaledWidthImage, 0, -(int) (newImageHeight - canVasHeight) / 2,
						null);
			} else {
				scaledWidthImage = originalImage.getScaledInstance(canVasWidth, canVasHeight,
						Image.SCALE_AREA_AVERAGING);
				zoomedImage = new BufferedImage(canVasWidth, canVasHeight, originalImage.getType());
				zoomedImage.getGraphics().drawImage(scaledWidthImage, 0, 0, null);
			}
		}
		return zoomedImage;
	}

	/***
	 * implement BORDERS option for ImageManage RDC<br>
	 * BORDERS : Add borders left and right or above and below (keep ratio with
	 * borders)
	 * 
	 * @param originalImage
	 *            image need to be implemented borders option
	 * @param canVasWidth
	 *            width of widget
	 * @param canVasHeight
	 *            height of widget
	 * @return BufferedImage image after bordering
	 */
	public static BufferedImage borderImage(BufferedImage originalImage, int canVasWidth, int canVasHeight) {

		int[] borderOptionResult = border(originalImage.getWidth(), originalImage.getHeight(), canVasWidth,
				canVasHeight);
		int x = borderOptionResult[2];
		int y = borderOptionResult[3];
		int newWidth = borderOptionResult[0];
		int newHeight = borderOptionResult[1];
		Image finalimage = originalImage.getScaledInstance(newWidth - 1, newHeight, Image.SCALE_AREA_AVERAGING);
		BufferedImage borderImage = new BufferedImage(canVasWidth, canVasHeight, BufferedImage.TYPE_INT_ARGB);
		borderImage.getGraphics().drawImage(finalimage, x, y, Color.WHITE, null);

		return borderImage;
	}

	/**
	 * calculate image base on border option
	 * 
	 * @param width
	 *            width of image
	 * @param height
	 *            height of image
	 * @param fixWidth
	 *            canvas width
	 * @param fixHeight
	 *            canvas height
	 * @return scale-width,scale-height,x-location, y-location
	 */
	private static int[] border(int width, int height, int fixWidth, int fixHeight) {
		int newWidth = 0;
		int newHeight = 0;
		int x = 0;
		int y = 0;

		if (width <= fixWidth && height <= fixHeight) {
			newWidth = width;
			newHeight = height;
		} else {
			if (width > fixWidth) {
				newWidth = fixWidth;
				newHeight = new Long(Math.round(newWidth * (height * 1.0 / width))).intValue();
			} else {
				newHeight = fixHeight;
				newWidth = new Long(Math.round(newHeight * (width * 1.0 / height))).intValue();
			}

			if (newHeight > fixHeight || newWidth > fixWidth) {
				int i = 0;

				while (true) {
					i++;
					if (i == 10) {
						break;
					}

					int[] result = borderHelper(newWidth, newHeight, fixWidth, fixHeight);
					newWidth = result[0];
					newHeight = result[1];

					if (newHeight > fixHeight || newWidth > fixWidth) {
						continue;
					} else {
						break;
					}
				}
			}

		}

		x = (fixWidth - newWidth) / 2;
		y = (fixHeight - newHeight) / 2;

		return new int[] { newWidth, newHeight, x, y };
	}

	/**
	 * calculate helper for border option
	 * 
	 * @param width
	 *            width of image
	 * @param height
	 *            height of image
	 * @param fixWidth
	 *            canvas's width
	 * @param fixHeight
	 *            cavas's height
	 * @return scale-width, scale-height
	 */
	private static int[] borderHelper(int width, int height, int fixWidth, int fixHeight) {
		int newWidth = 0;
		int newHeight = 0;

		if (width > fixWidth) {
			newHeight = fixHeight;
			newWidth = new Long(Math.round(newHeight * (width * 1.0 / height))).intValue();
		} else {
			newWidth = fixWidth;
			newHeight = new Long(Math.round(newWidth * (height * 1.0 / width))).intValue();

		}

		return new int[] { newWidth, newHeight };

	}

	/***
	 * implement STRETCH option for ImageManage RDC<br>
	 * STRETCH : stretch the image so it fits available space
	 * 
	 * @param originalImage
	 *            image need to be implemented stretch option
	 * @param canVasWidth
	 *            width of widget
	 * @param canVasHeight
	 *            height of widget
	 * @return BufferedImage image after stretching
	 */
	public static BufferedImage stretchImage(BufferedImage originalImage, int canVasWidth, int canVasHeight) {
		Image finalimage = originalImage.getScaledInstance(canVasWidth - 1, canVasHeight, Image.SCALE_AREA_AVERAGING);
		BufferedImage temp = new BufferedImage(canVasWidth, canVasHeight, BufferedImage.TYPE_INT_ARGB);
		temp.getGraphics().drawImage(finalimage, 0, 0, Color.WHITE, null);

		return temp;
	}

	/**
	 * resize the param image with type is binary
	 * 
	 * @author nndiem
	 * @param origianlImage
	 *            ,width,height
	 * @return binary
	 * @throws IOException
	 */
	public static byte[] resizeImageBinary(byte[] originalImage, int width, int height) throws IOException {
		if (width == 0) {
			width = 32;
		}
		if (height == 0) {
			height = 32;
		}
		// convert binary image to bufferedImage
		InputStream in = new ByteArrayInputStream(originalImage);
		BufferedImage originalImageBuffer = ImageIO.read(in);

		// resize buffered image after convert: after resize, the buffered
		// image is returned
		Image finalImage = originalImageBuffer.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING);
		BufferedImage resizedImage = new BufferedImage(width, height, originalImageBuffer.getType());
		resizedImage.getGraphics().drawImage(finalImage, 0, 0, null);

		// convert bufferedImage to binary
		ByteArrayOutputStream bytes = new ByteArrayOutputStream();
		ImageIO.write(resizedImage, "png", bytes);
		bytes.close();

		return bytes.toByteArray();
	}

	public static BufferedImage resizeImage(BufferedImage originalImage, int widthParam, int heightParam) {
		int width = widthParam;
		int height = heightParam;
		BufferedImage resizedImage;
		Image finalImage = originalImage.getScaledInstance(width, height, Image.SCALE_AREA_AVERAGING);
		resizedImage = new BufferedImage(width, height, originalImage.getType());
		resizedImage.getGraphics().drawImage(finalImage, 0, 0, null);

		return resizedImage;
	}
}
